package com.eurobcoin.user;

import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.ArrayList;
import java.util.List;

import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;

import com.eurobcoin.EurobcoinTable;
import com.eurobcoin.dao.mapper.UserMapper;
import com.eurobcoin.dao.mapper.UserRoleMapper;
import com.eurobcoin.dao.mapper.UserToRoleMapper;
import com.eurobcoin.dao.mapper.UserToUserMapper;
import com.eurobcoin.dao.model.User;
import com.eurobcoin.dao.model.UserExample;
import com.eurobcoin.dao.model.UserRole;
import com.eurobcoin.dao.model.UserRoleExample;
import com.eurobcoin.dao.model.UserToRole;
import com.eurobcoin.dao.model.UserToRoleExample;
import com.eurobcoin.dao.model.UserToUser;
import com.eurobcoin.dao.model.UserToRoleExample.Criteria;
import com.eurobcoin.helper.PasswdHelper;

public class UserManager {

	public List<UserModel> getAllUsers(SqlSession sqlSession) {
		UserMapper mapper = sqlSession.getMapper(UserMapper.class);
		UserExample userExample = new UserExample();
		userExample.setOrderByClause("usr_name ASC");
		
		List<User> usersList = mapper.selectByExample(userExample);
		List<UserModel> list = new ArrayList<UserModel>();
		
		for(User user : usersList) {
			
			UserModel userModel = this.daoUserToUserModel(sqlSession, user);
			list.add(userModel);
			
		}
		
		return list;
	}
	
	public void getPagedUserList(
			SqlSession sqlSession, 
			EurobcoinTable usersTable, 
			int page) {
		
		usersTable.clearRows();
		
		UserMapper mapper = sqlSession.getMapper(UserMapper.class);
		UserExample example = new UserExample();
		example.setOrderByClause("usr_id ASC");
		
		int offset = (page - 1) * EurobcoinTable.ROWS_PER_PAGE;
		RowBounds rowBounds = new RowBounds(offset, EurobcoinTable.ROWS_PER_PAGE);
		
		List<User> userList = mapper.selectByExampleWithRowbounds(example, rowBounds);
				
		// cuento todos los elementos
		int count = mapper.countByExample(example);

		usersTable.setTotalElements(count);
		usersTable.setSelectedPage(page);
		
		for(User user : userList) {
			
			UserModel userModel = this.daoUserToUserModel(sqlSession, user);
			usersTable.addRow(userModel);
		}
		
	}
	
	private UserModel daoUserToUserModel(SqlSession sqlSession, User user) {
		
		UserModel userModel = new UserModel();
		
		userModel.setEmail(user.getUsr_email());
		userModel.setId(user.getUsr_id());
		userModel.setLocale(user.getUsr_locale());
		userModel.setName(user.getUsr_name());
		userModel.setPassword(user.getUsr_password());
		userModel.setSalt(user.getUsr_salt());
		
		boolean emailConfirmed = "Y".equals(user.getUsr_confirmed());
		userModel.setEmailConfirmed(emailConfirmed);
		
		int userRoleId = this.getUserRoleById(sqlSession, userModel.getId());
		String userRoleText = this.getTextualUserRoleById(sqlSession, userRoleId);
		
		userModel.setRole(userRoleId);
		userModel.setTextualRole(userRoleText);
		
		return userModel;
		
	}

	public String getTextualUserRoleById(SqlSession sqlSession, int roleId) {
		
		String ret = null;
		
		UserRoleMapper mapper = sqlSession.getMapper(UserRoleMapper.class);
		UserRoleExample example = new UserRoleExample();
		UserRoleExample.Criteria criteria = example.createCriteria();
		criteria.andTur_role_idEqualTo(roleId);
		
		List<UserRole> userRoleList = mapper.selectByExample(example);
		
		if(userRoleList.size() > 0) {
			UserRole userRole = userRoleList.get(0);
			ret = userRole.getTur_role_name();
		}
		
		return ret;
	}
	
	public Integer getUserRoleById(SqlSession sqlSession, int userId) {
		
		Integer ret = null;
		
		UserToRoleMapper userToRoleMapper = sqlSession.getMapper(UserToRoleMapper.class);
		UserToRoleExample userToRoleExample = new UserToRoleExample();
		
		Criteria criteria = userToRoleExample.createCriteria();
		criteria.andUsr_idEqualTo(userId);
		
		List<UserToRole> userToRoleList = userToRoleMapper.selectByExample(userToRoleExample);
		if(userToRoleList.size() > 0) {
			UserToRole userToRole = userToRoleList.get(0);
			ret = userToRole.getTur_role_id(); 
		}
			
		return ret;
	}
	
	public List<UserRole> getUserRoles(SqlSession sqlSession) {
		
		UserRoleMapper mapper = sqlSession.getMapper(UserRoleMapper.class);
		List<UserRole> ret = mapper.selectByExample(new UserRoleExample());
		
		return ret;
		
	}
	
	public int saveUser(
			SqlSession sqlSession,
			String salt,
			String hashedPassword,
			String name,
			String email,
			boolean emailConfirmed,
			String locale,
			int rol,
			int invitingUserId) {
		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		UserExample userExample = new UserExample();
		
		UserExample.Criteria userCriteria = userExample.createCriteria();
		userCriteria.andUsr_emailEqualTo(email);
		
		int count = userMapper.countByExample(userExample);
		
		if(count != 0)
			return UserConst.USR_SAVE_REPEATED_EMAIL;
		
		userExample = new UserExample();
		
		userCriteria = userExample.createCriteria();
		userCriteria.andUsr_nameEqualTo(name);
		
		count = userMapper.countByExample(userExample);
		
		if(count != 0)
			return UserConst.USR_SAVE_REPEATED_USERNAME;
		
		User user = new User();
		
		user.setUsr_confirmed(emailConfirmed ? "Y" : "N");
		user.setUsr_email(email);
		user.setUsr_locale(locale);
		user.setUsr_name(name);
		user.setUsr_password(hashedPassword);
		user.setUsr_salt(salt);
		
		userMapper.insert(user);
		
		UserToRole userToRole = new UserToRole();
		userToRole.setTur_role_id(rol);
		userToRole.setUsr_id(user.getUsr_id());
		
		UserToRoleMapper userToRoleMapper = sqlSession.getMapper(UserToRoleMapper.class);
		
		userToRoleMapper.insert(userToRole);
		
		if(invitingUserId != 0) {
			UserToUserMapper utuMapper = sqlSession.getMapper(UserToUserMapper.class);
			UserToUser utu = new UserToUser();
			utu.setInvited_by(invitingUserId);
			utu.setUsr_id(user.getUsr_id());
			
			utuMapper.insert(utu);
		}
		
		return UserConst.USR_SAVE_OK;
	}
	
	public UserModel getUserById(SqlSession sqlSession, int userId) {
		
		UserMapper mapper = sqlSession.getMapper(UserMapper.class);
		User user = mapper.selectByPrimaryKey(userId);
		
		UserModel ret = this.daoUserToUserModel(sqlSession, user);
		
		return ret;
		
	}
	
	public UserModel getUserByEmail(SqlSession sqlSession, String email) {
		
		UserMapper mapper = sqlSession.getMapper(UserMapper.class);
		UserExample example = new UserExample();
		UserExample.Criteria criteria = example.createCriteria();
		
		criteria.andUsr_emailEqualTo(email);
		
		List<User> userList = mapper.selectByExample(example);
		
		UserModel ret = null;
		
		if(userList.size() > 0)
			ret = this.daoUserToUserModel(sqlSession, userList.get(0));
		
		return ret;
	}
	
	public UserModel getUserByUsername(SqlSession sqlSession, String username) {
		
		UserMapper mapper = sqlSession.getMapper(UserMapper.class);
		UserExample example = new UserExample();
		UserExample.Criteria criteria = example.createCriteria();
		
		criteria.andUsr_nameEqualTo(username);
		
		List<User> userList = mapper.selectByExample(example);
		
		UserModel ret = null;
		
		if(userList.size() > 0)
			ret = this.daoUserToUserModel(sqlSession, userList.get(0));
		
		return ret;
	}
	
	public void updateUserPassword(SqlSession sqlSession, int userId, String password) throws NoSuchAlgorithmException, NoSuchProviderException {
		String salt = PasswdHelper.generateSalt();
		String saltedPassword = salt + password + salt;
		
		String sha512 = PasswdHelper.getSHA512Hash(saltedPassword);
		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		User user = userMapper.selectByPrimaryKey(userId);
		
		user.setUsr_password(sha512);
		user.setUsr_salt(salt);
		
		userMapper.updateByPrimaryKey(user);
	}
	
	public void updateUser(
			SqlSession sqlSession, 
			int userId, 
			String name, 
			String email, 
			boolean emailConfirmed, 
			String locale, 
			int rol) {
		
		UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
		User user = userMapper.selectByPrimaryKey(userId);
		
		user.setUsr_confirmed(emailConfirmed ? "Y" : "N");
		user.setUsr_email(email);
		user.setUsr_locale(locale);
		user.setUsr_name(name);
		
		userMapper.updateByPrimaryKey(user);
		
		UserToRoleMapper userToRoleMapper = sqlSession.getMapper(UserToRoleMapper.class);
		UserToRoleExample userToRoleExample = new UserToRoleExample();
		Criteria criteria = userToRoleExample.createCriteria();
		criteria.andUsr_idEqualTo(userId);
		
		userToRoleMapper.selectByExample(userToRoleExample);
		
		UserToRole userToRole = new UserToRole();
		userToRole.setTur_role_id(rol);
		userToRole.setUsr_id(userId);
		
		userToRoleMapper.updateByExample(userToRole, userToRoleExample);
	}
	
	public String generateUniqueUsername(SqlSession sqlSession) {
		
		String username = null;
		
		int count = -1;
		
		while(count != 0) {
			username = this.generateRandomUsername();
		
			UserMapper mapper = sqlSession.getMapper(UserMapper.class);
			UserExample example = new UserExample();
			UserExample.Criteria criteria = example.createCriteria();
			criteria.andUsr_nameEqualTo(username);
			
			count = mapper.countByExample(example);
		}
		
		return username;
		
	}
	
	private String generateRandomUsername() {
		StringBuilder ret = new StringBuilder();
		
		// genero una letra aleatoria
		int cLetra = PasswdHelper.showRandomInt(97, 122);
		ret.append((char)cLetra);
		
		for(int i = 0; i < 8; i++) {
			ret.append(PasswdHelper.showRandomInt(0, 9));
		}
		
		return ret.toString();
	}
	
	public int getRoleIdByName(
			SqlSession sqlSession, 
			String rolename) {
		
		UserRoleMapper mapper = sqlSession.getMapper(UserRoleMapper.class);
		UserRoleExample example = new UserRoleExample();
		UserRoleExample.Criteria criteria = example.createCriteria();
		criteria.andTur_role_nameEqualTo(rolename);
		
		List<UserRole> userRoleList = mapper.selectByExample(example);
		
		int ret = 0;
		
		if(userRoleList.size() > 0)
			ret = userRoleList.get(0).getTur_role_id();
		
		return ret;
	}
	
}
